package com.jishuo.nontax.api.socket;

import com.jishuo.base.bean.BaseResult;
import com.jishuo.base.bean.ErrorCodeEnum;
import com.jishuo.base.config.NonTaxConfig;
import com.jishuo.base.util.SpringContextUtil;
import org.dom4j.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.Socket;

/**
 * socket接口服务，报文接收、处理、返回
 *
 * @author jhb
 * @date 2023-1-29
 */
public class ServerRecvThread implements Runnable {
    private static Logger logger = LoggerFactory.getLogger(ServerRecvThread.class);
    private Socket socket;

    public ServerRecvThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            NonTaxConfig nonTaxConfig = (NonTaxConfig) SpringContextUtil.getBean("nonTaxConfig");
            boolean setErrCode = nonTaxConfig.API_Socket_ReturnCode; // 返回报文中是否增加错误码
            // 报文字符集设置，default - 使用默认字符集
            String charset = nonTaxConfig.API_Socket_Charset;
            boolean setChar = !"default".equals(charset); // 是否需要字符集转换
            int sizeLen = nonTaxConfig.API_Socket_PreLen;   //报文长度

            socket.setSoTimeout(nonTaxConfig.API_Socket_TimeOut); //设置超时时间

            InputStreamReader isr = (!setChar) ? new InputStreamReader(socket.getInputStream()) : new InputStreamReader(socket.getInputStream(), charset);
            BufferedReader bfr = new BufferedReader(isr);
            OutputStreamWriter osw = (!setChar) ? new OutputStreamWriter(socket.getOutputStream()) : new OutputStreamWriter(socket.getOutputStream(), charset);
//            OutputStream os = socket.getOutputStream();
            PrintWriter pw = new PrintWriter(osw);
            String root = "";
            char[] target = new char[1024];
            int count = -1;
            logger.info("开始接收客户端[{}]消息", socket.getRemoteSocketAddress());
            while((count = bfr.read(target)) != -1) {
                root += new String(target, 0, count);
                if (root.indexOf("</root>") > 0) {
                    root = root.substring(0, root.indexOf("</root>") + 7);
                    break;
                }
            }
            logger.info("消息内容：" + root);
            if (sizeLen > 0) root = root.substring(sizeLen);

            String head = "";
            // 返回报文，body中内容
            String revBody;
            BaseResult result;
            try {
                // 解析xml报文
                Document doc = DocumentHelper.parseText(root);
                // 报文头，接口名称
                head = this.getNodeText(doc.selectSingleNode("//root/head")).trim();
                Element body = doc.getRootElement().element("body");
                if (body == null) {
                    revBody = "<bill><billstate>0</billstate></bill>";
                    result = new BaseResult(ErrorCodeEnum.API_PARSE_ERR);
                } else {
                    try {
                        result = ApiFactory.getApi(head).execute(head, body);
                        revBody = (String)result.getData();
                    } catch(Exception e) {
                        logger.info("接口处理错误。", e);
                        // 接口不存在
                        revBody = "<bill><billstate>0</billstate></bill>";
                        result = new BaseResult(ErrorCodeEnum.API_HEAD_ERR);
                    }
                }
            } catch (DocumentException ex) {
                logger.info("报文解析失败", ex);
                revBody = "<bill><billstate>0</billstate></bill>";
                result = new BaseResult(ErrorCodeEnum.API_PARSE_ERR);
            }

            // 设置错误信息，body内增加retCode和retMsg节点
            if (setErrCode) {
                if (!revBody.contains("<retCode>")) {
                    revBody = "<retCode>" + result.getCode() + "</retCode><retMsg>" + result.getMsg() + "</retMsg>" + revBody;
                }
            }

            String xml = "<root><head>" + head + "</head><body>" + revBody + "</body></root>";
            if (sizeLen > 0) {
                // 前端添加报文长度
                String tmp = "00000000000000000000" + xml.length();
                tmp = tmp.substring(tmp.length() - sizeLen);
                xml = tmp + xml;
            }
            pw.write(xml);
            pw.flush();
            logger.info("返回数据: "+xml);
            logger.info("关闭客户端[{}]", socket.getRemoteSocketAddress());
            pw.close();
            osw.close();
            bfr.close();
            isr.close();
        } catch (Exception e) {
            logger.info("处理socket请求异常。" + e.toString(), e);
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获得节点内容
     * @param node 节点
     * @return
     */
    private String getNodeText(Node node) {
        if (node == null) return "";
        return node.getText();
    }
}
